package com.kingyun.gpsinspection.purificationservice.services.iam.innerservice.accessory.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kingyun.gpsinspection.purificationservice.common.utils.IBMConstantUtil;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.Constant;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.ProcessBean;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.adm.AutoApply;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.adm.BusinessTravel;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.adm.TaskLinkIam;
import com.kingyun.gpsinspection.purificationservice.facade.model.iam.adm.VacationApply;
import com.kingyun.gpsinspection.purificationservice.facade.model.jsm.Employee;
import com.kingyun.gpsinspection.purificationservice.facade.service.iam.accessory.BPMService;
import com.kingyun.gpsinspection.purificationservice.facade.service.iam.adm.TaskLinkIamService;
import com.kingyun.gpsinspection.purificationservice.facade.service.jsm.OutEmployeeService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import sun.misc.BASE64Encoder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Java访问IBM REST API
 * Created by sugongche on 2016/12/19.
 * modify by lutianbo on 2017/1/17
 */
public class BPMServiceImpl implements BPMService {
    public Logger logger = LoggerFactory.getLogger(BPMServiceImpl.class);
    @Autowired
    private OutEmployeeService outEmployeeService;
    @Autowired
    private TaskLinkIamService taskLinkIamService;
    @Value("#{configProperties['baseURL']}")
    private String baseURL;
    @Value("#{configProperties['relativeURI']}")
    private String relativeURI;
    // 请假申请
    @Value("#{configProperties['vacation_bpdid']}")
    private String vacation_bpdid;
    // 出差申请
    @Value("#{configProperties['travel_bpdid']}")
    private String travel_bpdid;
    // 用车申请
    @Value("#{configProperties['car_bpdid']}")
    private String car_bpdid;
    // 查询的名称
    @Value("#{configProperties['queryName']}")
    private String queryName;
    // 待办
    @Value("#{configProperties['awaitTask']}")
    private String awaitTask;
    @Value("#{configProperties['iamProcessAppName']}")
    private String processAppName;
    @Value("#{configProperties['size']}")
    private String size;
    // 用户名
    @Value("#{configProperties['username']}")
    private String bpmUserName;
    // 密码
    @Value("#{configProperties['password']}")
    private String bpmPassword;

    /**
     * 开启流程
     *
     * @param url           api的访问url
     * @param bpdId         BPD 标识:以25开头
     * @param snapshotId    Snapshot 标识:以2064开头
     * @param branchId      分支标识::以2063开头
     * @param processAppId  流程应用程序标识:以2066开头
     * @param requestMethod 请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username      用户名
     * @param password      密码
     * @param parameter     参数
     * @return
     */
    @Override
    public String openBPM(String url, String bpdId, String snapshotId, String branchId, String processAppId, String requestMethod, String username, String password, String parameter) {
        // BPMAPI中开启流程的URL
        String callURL = url + "/rest/bpm/wle/v1/process?action=start";
        // BPD 标识:以25开头
        if (bpdId != null) {
            callURL = callURL + "&bpdId=" + bpdId;
        }
        // Snapshot 标识:以2064开头
        if (snapshotId != null) {
            callURL = callURL + "&snapshotId=" + snapshotId;
        }
        // 分支标识::以2063开头
        if (branchId != null) {
            callURL = callURL + "&branchId=" + branchId;
        }
        // 流程应用程序标识:以2066开头
        if (processAppId != null) {
            callURL = callURL + "&processAppId=" + processAppId;
        }
        // 参数
        if (parameter != null) {
            callURL = callURL + "&params=" + parameter;
        }
        // 执行后返回JSON
        if (callURL != null) {
            callURL = callURL + "&parts=all";
            return callRestAPI(callURL, requestMethod, username, password);
        } else {
            return null;
        }

    }

    /**
     * 开启流程
     * 请求：https://192.168.0.200:9443/rest/bpm/wle/v1/process?action=start&bpdId=25.b90b53fd-af89-4016-8eb1-f8de0bf994a9&snapshotId=2064.97ca58c9-1347-4364-ba33-b62e01297f6e&processAppId=2066.8595eceb-25b9-4234-842f-b6fd56ef6c79&parts=all
     * 方法： POST
     *
     * @param type      流程类型 0 请假 1出差 2 用车
     * @param username  用户名
     * @param password  密码
     * @param parameter 参数
     * @return
     */
    @Override
    public String openBPM(Integer type, String username, String password, String parameter) {
        // BPMAPI中开启流程的URL
        String callURL = baseURL + relativeURI + "/process?action=start";
        String bpdId = "";
        String processAppId = "";
        String snapshotId = "";

        ProcessBean bean = queryLatestVersion(type, username, password);
        if (bean != null) {
            bpdId = bean.getItemID();
            processAppId = bean.getProcessAppID();
            snapshotId = bean.getSnapshotID();
        }

        // BPD 标识:以25开头
        callURL = callURL + "&bpdId=" + bpdId;
        // Snapshot 标识:以2064开头
        callURL = callURL + "&snapshotId=" + snapshotId;
        // 流程应用程序标识:以2066开头
        callURL = callURL + "&processAppId=" + processAppId;
        // 参数
        if (parameter != null) {
            callURL = callURL + "&params=" + parameter;
        }

        // 执行后返回JSON
        callURL = callURL + "&parts=all";

        return callRestAPI(callURL, "POST", username, password);
    }

    /**
     * 根据任务类型查询任务最新版本的对象
     *
     * @param taskType
     * @param username
     * @param password
     * @return
     */
    @Override
    public ProcessBean queryLatestVersion(Integer taskType, String username, String password) {
        // 查询公开的流程
        String result = queryExposedProcess(username, password);

        if ("".equals(result)) {
            logger.info("查询公开的流程返回值为空串！");
            return null;
        } else {
            JSONObject resultObj = JSONObject.parseObject(result);
            if (resultObj != null) {
                String status = (String) resultObj.get("status");

                if (status != null && status.equals("200")) {
                    JSONObject dataObject = (JSONObject) resultObj.get("data");

                    JSONArray listArray = (JSONArray) dataObject.get("exposedItemsList");

                    List<ProcessBean> list = JSONArray.parseArray(JSONArray.toJSONString(listArray), ProcessBean.class);
                    //System.out.println(list);

                    ProcessBean processBean = queryLatestVersion(taskType, list);

                    return processBean;
                } else {
                    logger.error("查询公开的流程返回状态非200！");
                    return null;
                }
            } else {
                logger.error("查询公开的流程返回值非json字符串！！");
                return null;
            }
        }
    }

    /**
     * 遍历list，获得指定程序和流程的最新版本
     *
     * @param taskType
     * @param list
     * @return
     */
    @Override
    public ProcessBean queryLatestVersion(Integer taskType, List<ProcessBean> list) {
        // 程序名称为：综合管理
        List<ProcessBean> rwddglList = new ArrayList<>();
        for (ProcessBean bean : list) {
            if (IBMConstantUtil.ZHGL.equals(bean.getProcessAppName())) {
                rwddglList.add(bean);
            }
        }
        String display = "";
        // 休假
        if (taskType == 0) {
            display = IBMConstantUtil.XJSP;
            // 出差
        } else if (taskType == 1) {
            display = IBMConstantUtil.CCSQ;
            // 用车
        } else if (taskType == 2) {
            display = IBMConstantUtil.YCSQ;
        }

        //流程名称为display：并且有版本号，并且tip为false
        List<ProcessBean> targetProcessList = new ArrayList<>();
        for (ProcessBean bean : rwddglList) {
            if (display.equals(bean.getDisplay()) && bean.getSnapshotName() != null && bean.getTip() == false) {
                targetProcessList.add(bean);
            }
        }

        ProcessBean processBean = getMaxBean(targetProcessList);

        return processBean;
    }

    /**
     * 获取版本创建时间最大的bean
     *
     * @param list
     * @return
     */
    @Override
    public ProcessBean getMaxBean(List<ProcessBean> list) {
        // list 按某个字段排序：http://bbs.csdn.net/topics/240044985
        // 经过测试，如果list只有一个元素，也可以正常运行
        Collections.sort(list, new Comparator() {
            public int compare(Object o1, Object o2) {
                int flag = 0;

                //升序排列
                if ((o1 instanceof ProcessBean) && (o2 instanceof ProcessBean)) {
                    if (((ProcessBean) o1).getSnapshotCreatedOn() != null && ((ProcessBean) o2).getSnapshotCreatedOn() != null) {
                        flag = ((ProcessBean) o1).getSnapshotCreatedOn().compareTo(((ProcessBean) o2).getSnapshotCreatedOn());
                    }
                }

                return flag;
            }
        });

        ProcessBean processBean = null;
        if (list != null && list.size() > 0) {
            processBean = list.get(list.size() - 1);
        }

        return processBean;
    }

    /**
     * 查询公开的流程
     * 请求： https://192.168.0.200:9443/rest/bpm/wle/v1/exposed/process
     * 方法： GET
     * 状态： 200 - OK
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public String queryExposedProcess(String username, String password) {
        String callURL = baseURL + relativeURI + "/exposed/process";

        String result = callRestAPI(callURL, "GET", username, password);

        return result;
    }

    /**
     * 完成当前节点，往下一节点扭转
     *
     * @param url           api的访问callURL
     * @param tkiid         任务标识:
     * @param requestMethod 请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username      用户名
     * @param password      密码
     * @param parameter     参数
     */
    @Override
    public String completeTask(String url, String tkiid, String requestMethod, String username, String password, String parameter) {
        // BPMAPI中完成当前节点，往下一节点扭转的URL
        String callURL = url + "/rest/bpm/wle/v1/task/" + tkiid + "?action=finish";
        //完成当前节点，往下一节点扭转中的参数
        if (parameter != null) {
            callURL = callURL + "&params=" + parameter;
        }
        // 执行后返回JSON
        if (callURL != null) {
            callURL = callURL + "&parts=all";
            return callRestAPI(callURL, requestMethod, username, password);
        } else {
            return null;
        }
    }

    /**
     * 完成当前节点，往下一节点扭转
     * 请求： https://192.168.0.200:9443/rest/bpm/wle/v1/task/849?action=finish&parts=all
     * 方法： PUT
     * 状态： 200 - OK
     * 结果： 成功
     * {status: "200",
     * data: {...}
     * }
     * 结果：失败
     * {status: "error",
     * Data:{...}
     * }
     *
     * @param tkiid     任务标识:
     * @param username  用户名
     * @param password  密码
     * @param parameter 参数
     */
    @Override
    public String completeTask(String tkiid, String username, String password, String parameter) {
        // BPMAPI中完成当前节点，往下一节点扭转的URL
        if (tkiid.indexOf(",") != -1) {
            tkiid = tkiid.substring(tkiid.indexOf(",") + 1, tkiid.length());
        }
        System.out.println("》》》》》tkiid" + tkiid);
        String callURL = baseURL + "/rest/bpm/wle/v1/task/" + tkiid + "?action=finish";
        // 完成当前节点，往下一节点扭转中的参数
        if (parameter != null) {
            callURL = callURL + "&params=" + parameter;
        }
        // 执行后返回JSON
        callURL = callURL + "&parts=all";

        return callRestAPI(callURL, "PUT", username, password);
    }

    /**
     * 终止流程
     *
     * @param url           api的访问callURL
     * @param piid          流程实例标识:
     * @param requestMethod 请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username      用户名
     * @param password      密码
     */
    @Override
    public void terminateBPM(String url, String piid, String requestMethod, String username, String password) {
        String callURL = url + "/rest/bpm/wle/v1/process/" + piid;
        if (callURL != null) {
            callURL = callURL + "?action=terminate&parts=all";
            callRestAPI(callURL, requestMethod, username, password);
        }
    }

    /**
     * 删除流程
     *
     * @param url           api的访问url
     * @param piid          流程实例标识:
     * @param requestMethod 请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username      用户名
     * @param password      密码
     */
    @Override
    public void deleteBPM(String url, String piid, String requestMethod, String username, String password) {
        String callURL = url + "/rest/bpm/wle/v1/process/" + piid;
        if (callURL != null) {
            callURL = callURL + "?action=delete&parts=all";
            callRestAPI(callURL, requestMethod, username, password);
        }
    }

    /**
     * 查询流程
     *
     * @param url                 api的访问callURL
     * @param queryName           查询名称:
     * @param selectedAttributes  所选属性:
     * @param interactionFilter   交互过滤器: (待办、已办等)：
     * @param queryFilter         查询过滤器:
     * @param searchFilter        搜索过滤器:
     * @param processAppName      流程应用程序名称:
     * @param sortAttributes      排序属性:
     * @param offset              偏移量:
     * @param size                大小:
     * @param filterByCurrentUser
     * @param requestMethod       请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username            用户名
     * @param password            密码
     */
    @Override
    public String queryBPM(String url, String queryName, String selectedAttributes, String interactionFilter, String queryFilter, String searchFilter, String processAppName,
                           String sortAttributes, String offset, String size, String filterByCurrentUser, String requestMethod, String username, String password) {
        String callURL = url + "/rest/bpm/wle/v1/tasks/query/";
        ;
        if (queryName != null) {
            callURL = callURL + queryName + "?";
        }
        if (selectedAttributes != null) {
            callURL = callURL + "selectedAttributes=" + selectedAttributes;
        }
        if (selectedAttributes == null && interactionFilter != null) {
            callURL = callURL + "interactionFilter=" + interactionFilter;
        } else {
            callURL = callURL + "&interactionFilter=" + interactionFilter;
        }
        if (queryFilter != null) {
            callURL = callURL + "&queryFilter=" + queryFilter;
        }
        if (searchFilter != null) {
            callURL = callURL + "&params=" + searchFilter;
        }
        if (processAppName != null) {
            callURL = callURL + "&processAppName=" + processAppName;
        }
        if (sortAttributes != null) {
            callURL = callURL + "&sortAttributes=" + sortAttributes;
        }
        if (offset != null) {
            callURL = callURL + "&offset=" + offset;
        }
        if (size != null) {
            callURL = callURL + "&size=" + size;
        }
        if (filterByCurrentUser != null) {
            callURL = callURL + "&filterByCurrentUser=" + filterByCurrentUser;
        }
        if (callURL != null) {
            return callRestAPI(callURL, requestMethod, username, password);
        } else {
            return null;
        }
    }

    /**
     * 查询待办任务
     * 访问url=http://192.168.0.200:9080/rest/bpm/wle/v1/tasks/query/IBM.DEFAULTALLTASKSLIST_75?interactionFilter=ASSESS_AND_WORK_ON&processAppName=%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E7%AE%A1%E7%90%86"
     * 访问带版本号的url=http://192.168.0.200:9080/rest/bpm/wle/v1/tasks/query/IBM.DEFAULTALLTASKSLIST_75?interactionFilter=ASSESS_AND_WORK_ON&queryFilter=SNAPSHOT_NAME='v1.3.1'&processAppName=%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E7%AE%A1%E7%90%86
     *
     * @param username 用户名
     * @param password 密码
     * @throws Exception
     */
    @Override
    public String queryToDoTask(String username, String password, String version) throws Exception {
        String callURL = baseURL + relativeURI + "/tasks/query/IBM.DEFAULTALLTASKSLIST_75?";
        callURL += "interactionFilter=ASSESS_AND_WORK_ON";
        callURL += "&processAppName=" + processAppName;
        if (StringUtils.isNotBlank(version)) {
            callURL += "&queryFilter=SNAPSHOT_NAME='" + version + "'";
            //版本号为空：查询所有版本号
        }
        //必须加待办任务查询数量：否则默认查询20个待办任务
        callURL += "&size=" + size;
        String requestMethod = "GET";

        String result = callRestAPI(callURL, requestMethod, username, password);

        return result;
    }

    /**
     * 调用IBM BPM REST API
     *
     * @param urlString     api的访问url
     * @param requestMethod 请求的方式"GET"/"POST"/"PUT"/"DELETE"
     * @param username
     * @param password
     * @return json格式的字符串
     */
    @Override
    public String callRestAPI(String urlString, String requestMethod, String username, String password) {
        HttpURLConnection connection = null;
        String content = "";
        try {
            URL url = new URL(urlString);
            connection = (HttpURLConnection) url.openConnection();
            // Get：检索一个资源
            // POST：检索或者创建一个资源
            connection.setRequestMethod(requestMethod);
            // 设置用户名密码
            BASE64Encoder encoder = new BASE64Encoder();
            String encodedCredential = encoder.encode((username + ":" + password).getBytes());
            connection.setRequestProperty("Authorization", "Basic " + encodedCredential);
            // 获取调用结果
            connection.connect();
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                StringBuffer stringBuffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    stringBuffer.append(line);
                }
                content = stringBuffer.toString();
                System.out.println(content);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }

        return content;
    }

    /**
     * @param piid    任务标识id
     * @param toUser  要分配的用户
     * @param toGroup 要分配的组
     * @return
     */
    @Override
    public String assignTask(String piid, String toUser, String toGroup, String uName, String pword) {
        // 向用户分配
        String user = "";
        // 向组分配
        String group = "";
        try {
            // 若要分配的用户不为空
            if (StringUtils.isNotBlank(toUser)) {
                user = "&toUser=" + toUser;
            }
            // 若要分配的组不为空
            if (StringUtils.isNotBlank(toGroup)) {
                group = "&toGroup=" + toGroup;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 访问地址
        String callURL = baseURL + relativeURI + "/task/" + piid + "?action=assign" + user + group + "&parts=all";
        String requestMethod = "PUT";
        return callRestAPI(callURL, requestMethod, uName, pword);

    }

    @Override
    public void bpmDetail(Object record, String username, String password, Integer type) throws Exception {
        //处理人id
        String approveId;
        //任务id
        String taskId;

        /**
         * 区分 出差、用车、休假
         */
        if (type == Constant.car) {
            AutoApply autoApply = (AutoApply) record;
            approveId = autoApply.getApproveId();
            taskId = autoApply.getAutoApplyId();

        } else if (type == Constant.business) {
            BusinessTravel businessTravel = (BusinessTravel) record;
            approveId = businessTravel.getApproveId();
            taskId = businessTravel.getBusinessTravelId();
        } else {
            VacationApply vacationApply = (VacationApply) record;
            approveId = vacationApply.getApproveId();
            taskId = vacationApply.getVacationApplyId();
        }
        // 开启流程
        Employee employee = outEmployeeService.findById(approveId);
        String result = openBPM(type, username, password, null);
        JSONObject resultObj = JSONObject.parseObject(result);
        String status = (String) resultObj.get("status");
        //开始流程失败
        if (status != null && !"200".equals(status)) {
            throw new Exception("开启流程失败");
        }
        // 保存任务环节
        TaskLinkIam taskLink = new TaskLinkIam();
        taskLinkIamService.save(taskLink, result, type.shortValue(), taskId, Constant.note1);
        if (taskLink == null) {
            throw new Exception("保存任务环节失败");
        }
        // 分配给当前处理人
        String s1 = assignTask(taskLink.getTkiid(), URLEncoder.encode(username, "utf-8"), null, bpmUserName, bpmPassword);
        resultObj = JSONObject.parseObject(s1);
        String assignStatus = (String) resultObj.get("status");
        if (assignStatus != null && !"200".equals(assignStatus)) {
            throw new Exception("分配给当前申请人失败");
        }
        // 完成流程
        String s2 = completeTask(taskLink.getTkiid(), username, password, null);
        resultObj = JSONObject.parseObject(s2);
        String completeStatus = (String) resultObj.get("status");
        if (completeStatus != null && !"200".equals(completeStatus)) {
            throw new Exception("提交申请流程失败");
        }
        // 根据任务id查询下一节点任务标识
        String nextTkiid = nextTkiid(bpmUserName, bpmPassword, taskLink.getPiPiid());
        if (StringUtils.isEmpty(nextTkiid)) {
            throw new NullPointerException("任务标识为空");
        }
        // 指定下一节点处理人
        String s3 = assignTask(nextTkiid, URLEncoder.encode(employee.getLoginId(), "utf-8"), null, bpmUserName, bpmPassword);
        resultObj = JSONObject.parseObject(s3);
        String assign2Status = (String) resultObj.get("status");
        if (assign2Status != null && !"200".equals(assign2Status)) {
            throw new Exception("指定审批人失败");
        }
    }

    public String nextTkiid(String userName, String password, String pipiid) {
        String nextTkiid = "";
        try {
            Thread.sleep(1000);
            System.out.print("线程睡眠1秒！\n");
            nextTkiid = taskLinkIamService.queryBPMByPiid(userName, password, pipiid);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return nextTkiid;
    }
}
